<?php

namespace app\admin\controller\vv;

use app\admin\controller\Backend;
use app\admin\model\Abnormal;
use app\admin\model\Operation;
use app\admin\model\User;
use Carbon\Carbon;
use PhpOffice\PhpWord\IOFactory;
use PhpOffice\PhpWord\PhpWord;
use PhpOffice\PhpWord\Shared\Converter;

class Report extends Backend
{
    const STREET = ['福城街道', '观澜街道', '观湖街道', '大浪街道', '龙华街道', '民治街道'];

    public function day()
    {
        $requester = User::find($this->userId);
        if ($requester) {
            $nickname = $requester['nickname'];
        } else {
            $nickname = '';
        }
        $now  = time();
        $rows = Operation::with([
            'abnormal'
        ])->where('create_time', '>=', Carbon::createFromTimestamp($now, 'Asia/Shanghai')->startOfDay()->timestamp)->select()->each(function ($item) {
            $item['images']   = json_decode($item['images'], true);
            $item['scene']    = $this->scene($item);
            $item['times']    = $this->format_times($item);
            $item['distance'] = $this->format_distance($item);
            $item['duration'] = $this->format_duration($item);
        })->toArray();
        $this->jsonReturn([
            'code' => 0,
            'msg'  => 'success',
            'data' => [
                'time'     => Carbon::createFromTimestamp($now, 'Asia/Shanghai')->format('Y-m-d H:i:s'),
                'user'     => $nickname,
                'count'    => count($rows),
                'times'    => $this->sum_times($rows) . '(当日累计)',
                'duration' => $this->sum_duration($rows) . '分(当日累计)',
                'distance' => $this->sum_distance($rows) . '公里(当日累计)',
                'memo'     => implode(',', array_column($rows, 'description')),
                'items'    => $rows
            ]
        ]);
    }

    public function week()
    {
        $now         = time();
        $carbon_to   = Carbon::createFromTimestamp($now, 'Asia/Shanghai');
        $carbon_from = Carbon::createFromTimestamp($now, 'Asia/Shanghai')->subDays(7)->startOfDay();
        $center      = ['alignment' => 'center', 'spaceAfter' => 0];
        $word        = new PhpWord();
        $section     = $word->addSection();
        $rows        = Operation::field([
            'loitering_times',
            'loitering_distance',
            'loitering_duration',
            'operation_category',
            'exception_category',
            'description',
            'address',
            'images'
        ])->where('create_time', '>=', $carbon_from->timestamp)
            ->where('create_time', '<=', $carbon_to->timestamp)
            ->where('mark', 1)
            ->where('type', 'emergency')
            ->select()->each(function ($item) {
                $item['images']    = json_decode($item['images'], true);
                $item['danger_is'] = $item['operation_category'] == 1 ? 1 : 0;
                $item['fill_is']   = 0;
                $item['scene']     = $this->scene($item);
                $item['street']    = $this->street($item);
                $item['times']     = $this->format_times($item);
                $item['distance']  = $this->format_distance($item);
                $item['duration']  = $this->format_duration($item);
            })->toArray();

        // 一
        $section->addText('安全联动巡查周报', ['size' => 22], ['alignment' => 'center']);
        $section->addText($carbon_from->format('m月d日') . ' — ' . $carbon_to->format('m月d日'), ['color' => 'red'], $center);
        $section->addText('一、巡查总体情况', ['bold' => true]);
        $run = $section->addTextRun();
        $run->addText('        ');
        $run->addText(' 本周计划巡查任务 ');
        $run->addText(count($rows), ['color' => 'red']);
        $run->addText(' 次，实际完成巡查任务 ');
        $run->addText(count($rows), ['color' => 'red']);
        $run->addText(' 次。平均日执巡查任务 ');
        $run->addText(bcdiv(count($rows), 7, 2), ['color' => 'red']);
        $run->addText(' 次，累计飞行距离 ');
        $run->addText($this->sum_distance($rows), ['color' => 'red']);
        $run->addText(' 公里，累计飞行时长 ');
        $run->addText($this->sum_duration($rows), ['color' => 'red']);
        $run->addText(' 分钟。巡查中共发现隐患线索 ');
        $run->addText($this->sum_danger($rows), ['color' => 'red']);
        $run->addText(' 次，已对以上隐患完成线索信息闭环处置。');
        $section->addText('1、各街道巡查任务情况表', ['bold' => true]);
        $table = $section->addTable(['alignment' => 'center', 'cellSpacing' => 22]);
        $table->addRow(700);
        $table->addCell(2000, ['bgColor' => '#1e366a', 'valign' => 'center'])->addTextRun($center)->addText('归属街道');
        $table->addCell(1000, ['bgColor' => '#1e366a', 'valign' => 'center'])->addTextRun($center)->addText('巡查次数');
        $table->addCell(1500, ['bgColor' => '#1e366a', 'valign' => 'center'])->addTextRun($center)->addText('飞行距离(KM)');
        $table->addCell(2500, ['bgColor' => '#1e366a', 'valign' => 'center'])->addTextRun($center)->addText('飞行时长(min)');
        $table->addCell(1000, ['bgColor' => '#1e366a', 'valign' => 'center'])->addTextRun($center)->addText('巡查占比');
        $street_data = $this->street_data($rows);
        for ($i = 0; $i < count($street_data); $i++) {
            if ($i % 2 == 0) {
                $s = ['bgColor' => '#cfe0f6', 'valign' => 'center'];
            } else {
                $s = ['valign' => 'center'];
            }
            $table->addRow(700);
            $table->addCell('', $s)->addTextRun($center)->addText($street_data[$i][0]['street']);
            $table->addCell('', $s)->addTextRun($center)->addText($this->sum_times($street_data[$i]));
            $table->addCell('', $s)->addTextRun($center)->addText($this->sum_distance($street_data[$i]));
            $table->addCell('', $s)->addTextRun($center)->addText($this->sum_duration($street_data[$i]));
            $table->addCell('', $s)->addTextRun($center)->addText($this->scale($street_data, $i));
        }
        $table->addRow(700);
        $table->addCell('', ['bgColor' => '#1e366a', 'valign' => 'center'])->addTextRun($center)->addText('总计');
        $table->addCell('', ['bgColor' => '#1e366a', 'valign' => 'center'])->addTextRun($center)->addText($this->sum_times_dimension($street_data));
        $table->addCell('', ['bgColor' => '#1e366a', 'valign' => 'center'])->addTextRun($center)->addText($this->sum_distance_dimension($street_data));
        $table->addCell('', ['bgColor' => '#1e366a', 'valign' => 'center'])->addTextRun($center)->addText($this->sum_duration_dimension($street_data));
        $table->addCell('', ['bgColor' => '#1e366a', 'valign' => 'center'])->addTextRun($center)->addText('100%');
        $section->addTextBreak();
        $radar = $this->radar($street_data);
        $section->addText('2、各街道巡查次数对比分析图', ['bold' => true]);
        $section->addChart('radar', $radar['street'], $radar['times'], [
            'width'  => Converter::inchToEmu(5.5),
            'height' => Converter::inchToEmu(2)
        ]);
        $section->addText('3、场景类型情况及对比分析', ['bold' => true]);
        $scene_data = $this->scene_data($rows);
        $this->scene_str($scene_data, $section);
        $section->addChart('column', $scene_data['scenes'], $scene_data['times'], [
            'width'            => Converter::inchToEmu(5.5),
            'height'           => Converter::inchToEmu(4),
            'showLegend'       => true,
            'legendPosition'   => 't',
            'showAxisLabels'   => true,
            'showGridY'        => true,
            'dataLabelOptions' => [
                'showVal'     => false,
                'showCatName' => false,
            ]
        ], '巡查次数')->addSeries([], $scene_data['dangers'], '隐患数');


        // 二
        $section->addText('二、各街道巡查详细情况', ['bold' => true]);
        foreach ($street_data as $key => $rows_with_filled) {
            $section->addText($key + 1 . '.' . $rows_with_filled[0]['street'], ['bold' => true]);
            $run = $section->addTextRun();
            $run->addText(' 本周计划巡查 ');
            $run->addText($this->sum_times($rows_with_filled), ['color' => 'red']);
            $run->addText(' 次，累计完成巡查任务 ');
            $run->addText($this->sum_times($rows_with_filled), ['color' => 'red']);
            $run->addText(' 次，累计飞行距离 ');
            $run->addText($this->sum_distance($rows_with_filled), ['color' => 'red']);
            $run->addText(' 公里，累计飞行时长 ');
            $run->addText($this->sum_duration($rows_with_filled), ['color' => 'red']);
            $run->addText(' 分钟，发现 ');
            $run->addText($this->sum_danger($rows_with_filled), ['color' => 'red']);
            $run->addText(' 条安全隐患线索 ');
            foreach ($rows_with_filled as $k => $v) {
                if ($v['fill_is'] == 0) {
                    $section->addText('(' . ($k + 1) . ')' . $v['address']);
                    $section->addText('隐患线索: ' . $v['description']);
                    foreach ($v['images'] as $image) {
                        $section->addImage($image, ['width' => 222, 'alignment' => 'center']);
                    }
                }
            }
        }

        // 三
        $section->addText('三、下周巡查计划', ['bold' => true]);
        $section->addText('继续对建筑工地、道路交通等领域开展日常巡飞及回头看，对已发现的安全隐患线索进行复飞复查。');
        $table = $section->addTable(['alignment' => 'center', 'cellSpacing' => 22]);
        $table->addRow(700);
        $table->addCell(2000, ['bgColor' => '#1e366a', 'valign' => 'center'])->addTextRun($center)->addText('归属街道');
        $table->addCell(2000, ['bgColor' => '#1e366a', 'valign' => 'center'])->addTextRun($center)->addText('建筑工地');
        $table->addCell(2000, ['bgColor' => '#1e366a', 'valign' => 'center'])->addTextRun($center)->addText('道路交通');
        $table->addCell(2000, ['bgColor' => '#1e366a', 'valign' => 'center'])->addTextRun($center)->addText('总计');
        for ($i = 1; $i <= 6; ++$i) {
            if ($i % 2 == 0) {
                $s = ['bgColor' => '#cfe0f6', 'valign' => 'center'];
            } else {
                $s = ['valign' => 'center'];
            }
            $table->addRow(700);
            $table->addCell('', $s)->addTextRun($center)->addText('');
            $table->addCell('', $s)->addTextRun($center)->addText('');
            $table->addCell('', $s)->addTextRun($center)->addText('');
            $table->addCell('', $s)->addTextRun($center)->addText('');
        }
        $table->addRow(700);
        $table->addCell('', ['bgColor' => '#1e366a', 'valign' => 'center'])->addTextRun($center)->addText('总计');
        $table->addCell('', ['bgColor' => '#1e366a', 'valign' => 'center'])->addTextRun($center)->addText('');
        $table->addCell('', ['bgColor' => '#1e366a', 'valign' => 'center'])->addTextRun($center)->addText('');
        $table->addCell('', ['bgColor' => '#1e366a', 'valign' => 'center'])->addTextRun($center)->addText('');


//        IOFactory::createWriter($word)->save('a.docx');
        IOFactory::createWriter($word)->save('php://output');
    }

    private function format_times($item): int
    {
        $str = $item['loitering_times'] ?? '';
        preg_match('|(?P<number>\d+)|', $str, $matches);
        $r = $matches['number'] ?? 0;
        return (int)$r;
    }

    private function format_distance($item): string
    {
        return rtrim(strtolower($item['loitering_distance']), 'km');
    }

    private function format_duration($item): int
    {
        $str = $item['loitering_duration'] ?? '';
        preg_match('|(?P<number>\d+)|', $str, $matches);
        $number = $matches['number'] ?? 0;
        $number = (int)$number;
        $unit   = ltrim($item, $number);
        if ($unit == 'H' || $unit == 'h' || $unit == '小时') {
            return $number * 60;
        }
        return $number;
    }

    private function sum_times($rows): int
    {
        return array_reduce($rows, function ($carry, $item) {
            $carry += $item['times'];
            return $carry;
        }, 0);
    }

    private function sum_times_dimension($data): int
    {
        return array_reduce($data, function ($carry, $rows) {
            $carry += $this->sum_times($rows);
            return $carry;
        }, 0);
    }

    private function sum_distance($rows): string
    {
        return array_reduce($rows, function ($carry, $item) {
            return bcadd($carry, $item['distance'], 2);
        }, 0);
    }

    private function sum_distance_dimension($data): string
    {
        return array_reduce($data, function ($carry, $rows) {
            return bcadd($carry, $this->sum_distance($rows), 2);
        }, 0);
    }

    private function sum_duration($rows): int
    {
        return array_reduce($rows, function ($carry, $item) {
            $carry += $item['duration'];
            return $carry;
        }, 0);
    }

    private function sum_duration_dimension($data): int
    {
        return array_reduce($data, function ($carry, $rows) {
            $carry += $this->sum_duration($rows);
            return $carry;
        }, 0);
    }

    private function scale($data, int $i): string
    {
        if ($data[$i][0]['fill_is']) {
            return '0%';
        }
        $a = count($data[$i]);
        $b = 0;
        foreach ($data as $item) {
            if (!$item[0]['fill_is']) {
                $b += count($item);
            }
        }
        if (!$b) {
            return '0%';
        }
        return bcmul(bcdiv($a, $b, 4), 100, 2) . '%';
    }

    private function radar($data): array
    {
        $street = [];
        $times  = [];
        foreach ($data as $rows) {
            $street[] = $rows[0]['street'];
            $times[]  = array_sum(array_column($rows, 'times'));
        }
        return [
            'street' => $street,
            'times'  => $times,
        ];
    }

    private function sum_danger($rows): int
    {
        return array_reduce($rows, function ($carry, $item) {
            if ($item['danger_is'] ?? 0) {
                $carry++;
            }
            return $carry;
        }, 0);
    }

    private function scene($item): string
    {
        $id = $item['exception_category'] ?? 0;
        if (!$id) return '未知';
        $a = Abnormal::find($id);
        if (empty($a['pid'])) {
            return $a['name'];
        } else {
            $b = Abnormal::find($a['pid']);
            if (empty($b['pid'])) {
                return $b['name'];
            } else {
                $c = Abnormal::find($b['pid']);
                if (empty($c['pid'])) {
                    return $c['name'];
                } else {
                    $d = Abnormal::find($c['pid']);
                    return $d['name'] ?? '错误';
                }
            }
        }
    }

    private function street_data($rows): array
    {
        // 先补充数据
        foreach (array_diff(self::STREET, array_unique(array_column($rows, 'street'))) as $street) {
            $rows[] = [
                'street'   => $street,
                'times'    => 0,
                'distance' => 0,
                'duration' => 0,
                'fill_is'  => 1
            ];
        }
        $r = [];
        foreach ($rows as $item) {
            $r[$item['street']][] = $item;
        }
        return array_values($r);
    }

    private function street($item): string
    {
        $address = $item['address'] ?? '';
        foreach (self::STREET as $item) {
            if (str_contains($address, $item)) {
                return $item;
            }
        }
        return '';
    }

    private function scene_data($rows): array
    {
        $arr = [];
        foreach ($rows as $item) {
            $arr[$item['scene']][] = $item;
        }
        $keys = array_keys($arr);
        foreach (Abnormal::where('level', 1)->where('mark', 1)->where('model_type', 'emergency')->column('name') as $scene) {
            if (!in_array($scene, $keys)) {
                $arr[$scene] = [];
            }
        }
        $scenes  = [];
        $times   = [];
        $dangers = [];
        foreach ($arr as $scene => $rows) {
            $scenes[] = (string)$scene;
            if (empty($rows)) {
                $times[]   = 0;
                $dangers[] = 0;
            } else {
                $times[]   = array_sum(array_column($rows, 'times'));
                $dangers[] = array_reduce($rows, function ($carry, $row) {
                    if ($row['danger_is']) {
                        $carry++;
                    }
                    return $carry;
                }, 0);
            }
        }
        return [
            'scenes'  => $scenes,
            'times'   => $times,
            'dangers' => $dangers
        ];
    }

    private function scene_str($scene_data, $section)
    {
        $run = $section->addTextRun();
        $run->addText('         按场景类型区分，本周');
        array_map(function ($scene, $time, $danger) use ($run) {
            $run->addText($scene . '巡查 ');
            $run->addText($time, ['color' => 'red']);
            $run->addText(' 次，发现隐患数 ');
            $run->addText($danger, ['color' => 'red']);
            $run->addText(' 处。');
        }, $scene_data['scenes'], $scene_data['times'], $scene_data['dangers']);
    }
}